package com.shmet.tool.localcall.frame.factory;

import com.shmet.tool.localcall.frame.register.BizRegister;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.Objects;


/**
 * @author shmet
 * @date 2022/6/28 11:13
 * @desc
 */
public class BizProxyFactory<T> implements MethodInterceptor {

    private T obj;

    public BizProxyFactory(T obj) {
        this.obj = obj;
    }

    public T getProxy() {
        // 1. 创建Enhancer类对象，它类似于咱们JDK动态代理中的Proxy类，该类就是用来获取代理对象的
        Enhancer enhancer = new Enhancer();
        // 2. 设置父类的字节码对象。为啥子要这样做呢？因为使用CGLIB生成的代理类是属于目标类的子类的，也就是说代理类是要继承自目标类的
        enhancer.setSuperclass(this.obj.getClass());
        // 3. 设置回调函数
        enhancer.setCallback(this);
        // 4. 创建代理对象
        return (T) enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 从约定的参数中，根据基类取实体
        String module = this.getBaseParamByArgs(args);
        String type = this.getServNameByClass(this.obj.getClass());
        // 根据参数取示例对象
        Object instance = BizRegister.getServiceBean(module + type);
        if (Objects.nonNull(instance)) {
            // 换成要执行的示例的方法
            Method newMethod = instance.getClass().getMethod(method.getName(), method.getParameterTypes());
            return newMethod.invoke(instance, args);
        }
        return method.invoke(this.obj, args);
    }

    /**
     * @author shmet
     * @date 2022/6/28
     * @desc 获取ser名称
     */
    public String getServNameByClass(Class<?> objClass) {
        Class<?>[] interfaces = objClass.getInterfaces();
        if (interfaces != null && interfaces.length > 0) {
            Class<?> clazz = objClass.getInterfaces()[0];
            return clazz.getSimpleName();
        }
        return "";
    }

    /**
     * @author shmet
     * @date 2022/6/27
     * @desc 遍历取约定对象，假设关键参数在第一位
     */
    public String getBaseParamByArgs(Object[] args) {
        if (null != args && args.length > 0) {
            return args[0] + "";
        }
        return null;
    }
}
